package laxoffice

import (
	"encoding/csv"
	"io"
	"os"
)
// @Desc: 读取csv按行
// @param filePathAndName 文件完整路径+名字
// @param startLineNum 从第几行开始回调
// @param rowCallBack 每行回调
// @return error load结果
func CSVEachRow(filePathAndName string, startLineNum int, rowCallBack func(csvIndex int, csvRow []string) error)  error {
	if rowCallBack == nil {
		return nil
	}
	fs, err := os.Open(filePathAndName)
	if err != nil {
		return err
	}
	defer fs.Close()
	r := csv.NewReader(fs)
	var idx = 0
	for {
		row, err := r.Read()
		if err != nil {
			if err == io.EOF {
				break
			}
			return err
		}
		idx++
		if idx < startLineNum {
			continue
		}
		if err = rowCallBack(idx, row); err != nil {
			return err
		}
	}
	return nil
}

// @Desc: 读取全部csv
// @param filePathAndName 路径和名字
// @param startLineNum 从第几行开始读
// @return [][]string csv内容
// @return error 错误码
func LoadCSVAll(filePathAndName string, startLineNum int) ([][]string, error) {
	fs, err := os.Open(filePathAndName)
	if err != nil {
		return nil, err
	}
	defer fs.Close()
	r := csv.NewReader(fs)
	for i := 1; i < startLineNum; i++ {
		_, err = r.Read()
		if err != nil {
			return nil, err
		}
	}
	rows, err := r.ReadAll()
	if err != nil {
		return nil, err
	}
	return rows, nil
}

// @Desc: 写csv
type LaxCSVWriter struct {
	*csv.Writer
	f *os.File
	writeChan chan []string
	finishChan chan bool
}

// @Desc: 创建一个writer
// @param filePathAndName 路径+名字
// @param trunc 是否清空重写
// @return *LaxCSVWriter writer
// @return error
func NewLaxCSVWriter(filePathAndName string, trunc bool) (*LaxCSVWriter, error) {
	var fsFlag = os.O_WRONLY | os.O_CREATE
	if trunc {
		fsFlag |= os.O_TRUNC
	}
	fs, err := os.OpenFile(filePathAndName, fsFlag, 0666)
	if err != nil {
		return nil, err
	}
	if trunc {
		fs.WriteString("\xEF\xBB\xBF")
	}
	w := csv.NewWriter(fs)
	r := &LaxCSVWriter{
		Writer:     w,
		f:          fs,
		writeChan:  make(chan []string),
		finishChan: make(chan bool),
	}
	go r.writeInternal()
	return r, nil
}

// @Desc: 写一行数据,支持多协程写
// @receiver lcw
// @param line
func (lcw *LaxCSVWriter) WriteOneLine(line []string) {
	lcw.writeChan <- line
}

// @Desc: 协程写的具体实现
// @receiver lcw
func (lcw *LaxCSVWriter) writeInternal() {
	for record := range lcw.writeChan {
		lcw.Write(record)
	}
	lcw.finishChan <- true
}

// @Desc: 结束，写文件并关闭
// @receiver lcw
func (lcw *LaxCSVWriter) WaitFinish() {
	if lcw.writeChan != nil {
		close(lcw.writeChan)
	}
	if lcw.finishChan != nil {
		<-lcw.finishChan
		close(lcw.finishChan)
	}
	if lcw.Writer != nil {
		lcw.Writer.Flush()
		lcw.Writer = nil
	}
	if lcw.f != nil {
		lcw.f.Close()
		lcw.f = nil
	}
}
